/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-08-03 22:49:55
 * @LastEditTime: 2021-08-25 08:44:15
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */

#ifndef DRIVERS_FPCIE_H
#define DRIVERS_FPCIE_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "ft_types.h"
#include "ft_assert.h"
#include "f_pcie_dma.h"

#define FPCIE_ERR_INVALID_PARAM FT_CODE_ERR(ErrModBsp, ErrPcie, 0x1u)
#define FPCIE_ERR_OUTOF_BUS FT_CODE_ERR(ErrModBsp, ErrPcie, 0x2u)
#define FPCIE_ERR_CONFIG_WRITE FT_CODE_ERR(ErrModBsp, ErrPcie, 0x3u)
#define FPCIE_ERR_TYPE0 FT_CODE_ERR(ErrModBsp, ErrPcie, 0x4u)
#define FPCIE_ERR_TIMEOUT FT_CODE_ERR(ErrModBsp, ErrPcie, 0x5u)

#define FPCIE_BAR_0 0
#define FPCIE_BAR_1 1
#define FPCIE_BAR_2 2
#define FPCIE_BAR_3 3
#define FPCIE_BAR_4 4
#define FPCIE_BAR_5 5

#define FPCIE_PEU0_C0 0
#define FPCIE_PEU0_C1 1
#define FPCIE_PEU0_C2 2
#define FPCIE_PEU1_C0 3
#define FPCIE_PEU1_C1 4
#define FPCIE_PEU1_C2 5

/** @name Callback identifiers
 *
 * These constants are used as parameters to FXMAC_SetHandler()
 * @{
 */
#define FPCIE_HANDLER_DMASEND 1U
#define FPCIE_HANDLER_DMARECV 2U
#define FPCIE_HANDLER_DMASEND_ERROR 3U
#define FPCIE_HANDLER_DMARECV_ERROR 4U
    /*@}*/

    typedef void (*FPcieIrqCallBack)(void *args);

    typedef struct
    {
        u16 vendor, device;
    } FpcieId;

    typedef struct
    {
        u32 instance_id; /* Id of device*/
        u32 irq_num;     // Irq number
        uintptr_t ecam;  /* The Memory way */
        uintptr_t peu0_config_address;
        uintptr_t peu1_config_address;
        uintptr_t control_c0_address;
        uintptr_t control_c1_address;
        uintptr_t control_c2_address;
        uintptr_t control_c3_address;
        uintptr_t control_c4_address;
        uintptr_t control_c5_address;
        u64 npmem_base_addr;
        u64 pmem_base_addr;

    } FPcieConfig;

    typedef struct
    {
        u32 is_ready; /* Device is ininitialized and ready*/
        FPcieConfig config;

        FPcieIrqCallBack fpcie_dma_rx_cb;
        void *dma_rx_args;

        FPcieIrqCallBack fpcie_dma_tx_cb;
        void *dma_tx_args;

        FPcieIrqCallBack fpcie_dma_rx_error_cb;
        void *dma_rx_error_args;

        FPcieIrqCallBack fpcie_dma_tx_error_cb;
        void *dma_tx_error_args;

    } FPcie;

    FPcieConfig *FPcieLookupConfig(u32 instance_id);
    /**
     * @name: FPcieCfgInitialize
     * @msg:   This function initializes a Pcie instance/driver.
     * @param {FPcie} *instance_p is a pointer to the FPcie instance.
     * @param {FPcieConfig} *config_p  points to the FPcie device configuration structure.
     * @return {*}
     */
    ft_error_t FPcieCfgInitialize(FPcie *instance_p, FPcieConfig *config_p);

    /**
     * @name: FPcieDmaDescSet
     * @msg: This function set the descriptors.
     * @param {FPcieDmaDescriptor} *desc is a pointer to the dma transfer descriptor structure.
     * @param {u64} axi_addr  Axi Memory address
     * @param {u64} pcie_addr  Ep bar address
     * @param {u64} length  The length of data transmitted by a single descriptor
     * @param {FPcieDmaDescriptor} *next_desc The next descriptor to send
     * @return {*}
     */
    ft_error_t FPcieDmaDescSet(uintptr axi_addr,
                               uintptr pcie_addr,
                               u32 length,
                               struct FPcieDmaDescriptor *desc,
                               struct FPcieDmaDescriptor *next_desc);

    /**
     * @name: FPcieDmaRead
     * @msg:  This function use dma to read.
     * @param {intptr} cintrol_address  Peu control address.
     * @param {structFPcieDmaDescriptor} *desc The first address of the receive descriptor
     */
    void FPcieDmaRead(uintptr cintrol_address, struct FPcieDmaDescriptor *desc);

    /**
     * @name: FPcieDmaWrite
     * @msg:  This function use dma to write.
     * @param {intptr} cintrol_address  Peu control address.
     * @param {structFPcieDmaDescriptor} *desc The first address of the send descriptor
     */
    void FPcieDmaWrite(uintptr cintrol_address, struct FPcieDmaDescriptor *desc);

    /**
     * @name: FPcieDmaPollDone
     * @msg: Wait for the DMA polling to complete
     * @param {structFPcieDmaDescriptor} *desc The first address of the send descriptor
     * @param {u32} wait_cnt 
     * @return {*}
     */
    ft_error_t FPcieDmaPollDone(struct FPcieDmaDescriptor *desc, u32 wait_cnt);

    int FPcieEpSetBar(FPcie *instance_p, u32 peu_num, u32 bar_num, u64 bar_mem_addr, u64 bar_mem_size, int flags);
    int FPcieEpCleanBar(FPcie *instance_p, u32 peu_num, u32 bar_num);
    int FPcieEpMapAddr(FPcie *instance_p, u32 peu_num, u64 phy_addr, u64 pcie_addr, u64 size);

    /**
     * @name: FPcieFetchDeviceInBus
     * @msg:  This function starts PCIe enumeration.
     * @param {FPcie} *instance_p is a pointer to the FPcie instance.
     * @param {uint32_t} bus_num to scans for connected bridges/endpoints on it.
     */
    void FPcieFetchDeviceInBus(FPcie *instance_p, uint32_t bus_num);
    u64 FPcieFindBusDeviceBarAddress(FPcie *instance_p, FpcieId *check_id_p, u32 bus_num, u32 bar);

    /* IRQ */
    LONG FPcieSetHandler(FPcie *instance_p, u32 handler_type,
                         void *func_pointer, void *call_back_ref);
    void FPcieMiscIrq(s32 vector, void *args);

    /* option */
    void FPcieMiscIrqSet(FPcie *instance_p, fsize_t peu_num);
    void FPcieMiscIrqClear(FPcie *instance_p, fsize_t peu_num);
#ifdef __cplusplus
}
#endif

#endif // !
